home *** CD-ROM | disk | FTP | other *** search
/ Aminet 24 / Aminet 24 (1998)(GTI - Schatztruhe)[!][Apr 1998].iso / Aminet / comm / mail / Mutt089src.lha / Mutt-0.89i-AMIGA / src / rfc822.c < prev    next >
C/C++ Source or Header  |  1998-01-28  |  10KB  |  588 lines

  1. /*
  2.  * Copyright (C) 1996-8 Michael R. Elkins <me@cs.hmc.edu>
  3.  * 
  4.  *     This program is free software; you can redistribute it and/or modify
  5.  *     it under the terms of the GNU General Public License as published by
  6.  *     the Free Software Foundation; either version 2 of the License, or
  7.  *     (at your option) any later version.
  8.  * 
  9.  *     This program is distributed in the hope that it will be useful,
  10.  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  *     GNU General Public License for more details.
  13.  * 
  14.  *     You should have received a copy of the GNU General Public License
  15.  *     along with this program; if not, write to the Free Software
  16.  *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  */ 
  18.  
  19. #include "mutt.h"
  20.  
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <stdlib.h>
  24. #include <ctype.h>
  25.  
  26. /* special chars from RFC822 */
  27. const char *rspecials = "@<>()[];:.,\\\"";
  28.  
  29. /* MIME specials */
  30. const char *tspecials = "@<>()[];:.,\\\"?/=";
  31.  
  32. /* word specials */
  33. const char *wspecials = " @<>()[];:,\\\"";
  34.  
  35. /* ----------------------------------------------------------------------------
  36.  * RFC822 parsing routines
  37.  */
  38.  
  39. static const char *parse_comment (const char *s, char *comment, size_t len)
  40. {
  41.   int n = 1;
  42.  
  43.   if (comment)
  44.     len--; /* save room for the terminal \0 */
  45.   else
  46.     len = 0;
  47.  
  48.   while (*s)
  49.   {
  50.     if (*s == '\\')
  51.     {
  52.       s++;
  53.       if (! *s)
  54.     break; /* don't move past a nul */
  55.     }
  56.     else if (*s == '(')
  57.       n++;
  58.     else if (*s == ')')
  59.     {
  60.       n--;
  61.       if (n == 0)
  62.       {
  63.     s++;
  64.     break;
  65.       }
  66.     }
  67.     else if (ISSPACE (*s))
  68.     {
  69.       /* collapse whitespace runs to a single char */
  70.       SKIPWS (s);
  71.       if (len)
  72.       {
  73.     *comment++ = ' '; /* convert to a single space */
  74.     len--;
  75.       }
  76.       continue;
  77.     }
  78.  
  79.     if (len)
  80.     {
  81.       *comment++ = *s;
  82.       len--;
  83.     }
  84.  
  85.     s++;
  86.   }
  87.  
  88.   if (comment)
  89.     *comment = 0;
  90.  
  91.   return (s);
  92. }
  93.  
  94. static const char *parse_quote (const char *s, char *quote, size_t len)
  95. {
  96.   while (*s)
  97.   {
  98.     if (*s == '\\')
  99.     {
  100.       s++;
  101.       if (!*s)
  102.     break; /* don't move past a null */
  103.     }
  104.     else if (*s == '\"')
  105.     {
  106.       s++;
  107.       break;
  108.     }
  109.  
  110.     if (len > 1)
  111.     {
  112.       *quote++ = *s;
  113.       len--;
  114.     }
  115.  
  116.     s++;
  117.   }
  118.   *quote = 0;
  119.   return s;
  120. }
  121.  
  122. static void parse_mailbox (ADDRESS *a, const char *s, const char *host)
  123. {
  124.   char *p;
  125.  
  126.   if ((p = strrchr (s, '@')) != NULL)
  127.   {
  128.     *p++ = 0;
  129.     a->host = safe_strdup (p);
  130.   }
  131.   else
  132.     a->host = safe_strdup (host);
  133.  
  134.   a->mailbox = safe_strdup (s);
  135. }
  136.  
  137. static const char *parse_addrspec (ADDRESS *a, const char *s, const char *host)
  138. {
  139.   char buf[1024];
  140.   char *p = buf;
  141.   size_t buflen = sizeof (buf);
  142.  
  143.   while (*s)
  144.   {
  145.     if (*s == '(')
  146.     {
  147.       /* ignore comments inside of <> */
  148.       s = parse_comment (s, NULL, 0);
  149.     }
  150.     else if (*s == '\"')
  151.     {
  152.       size_t len;
  153.  
  154.       /* FOO - this assumes that the quoted-string is the first word in the
  155.        * addrspec.
  156.        */
  157.       s = parse_quote (s + 1, buf, sizeof (buf));
  158.       len = strlen (buf);
  159.       buflen = sizeof (buf) - len;
  160.       p = buf + len;
  161.     }
  162.     else if (*s == ':')
  163.     {
  164.       /* routing info. */
  165.       *p = 0;
  166.       safe_free ((void **) &a->adl);
  167.       a->adl = safe_strdup (buf);
  168.       p = buf;
  169.       buflen = sizeof (buflen);
  170.       s++;
  171.     }
  172.     else if (*s == '>')
  173.     {
  174.       /* end of address */
  175.       s++;
  176.       break;
  177.     }
  178.     else if (ISSPACE (*s))
  179.     {
  180.       /* skip all whitespace */
  181.       s++;
  182.     }
  183.     else
  184.     {
  185.       if (buflen > 1)
  186.     *p++ = *s;
  187.       s++;
  188.     }
  189.   }
  190.   *p = 0;
  191.  
  192.   if (buf[0])
  193.     parse_mailbox (a, buf, host);
  194.  
  195.   return (s);
  196. }
  197.  
  198. static const char *parse_address (ADDRESS **a, const char *s, const char *host)
  199. {
  200.   ADDRESS *tmp = mutt_new_address ();
  201.   char addr[1024];
  202.   char buf[1024];
  203.   char *p = addr;
  204.   size_t addrlen = sizeof (addr);
  205.  
  206.   while (*s)
  207.   {
  208.     if (*s == '(')
  209.     {
  210.       s = parse_comment (s + 1, buf, sizeof (buf));
  211.       if (!tmp->personal)
  212.     tmp->personal = safe_strdup (buf);
  213.     }
  214.     else if (*s == '\"')
  215.     {
  216.       s = parse_quote (s + 1, p, addrlen);
  217.       while (*p)
  218.       {
  219.     p++;
  220.     addrlen--;
  221.       }
  222.     }
  223.     else if (*s == ':')
  224.     {
  225.       /* group mailbox format */
  226.       *p = 0;
  227.       tmp->mailbox = safe_strdup (addr);
  228.  
  229.       /* reset */
  230.       p = addr;
  231.       addrlen = sizeof (addr);
  232.  
  233.       s++;
  234.       break;
  235.     }
  236.     else if (*s == ';')
  237.     {
  238.       /* end of group mailbox */
  239.       *p = 0;
  240.       if (addr[0])
  241.     parse_mailbox (tmp, addr, host);
  242.  
  243.       if (tmp->mailbox)
  244.       {
  245.     /* create a null entry as group terminator */
  246.     tmp->next = mutt_new_address ();
  247.       }
  248.  
  249.       *a = tmp;
  250.  
  251.       return (s + 1);
  252.     }
  253.     else if (*s == '<')
  254.     {
  255.       /* start of real address */
  256.       *p = 0;
  257.       if (addr[0] && !tmp->personal)
  258.     tmp->personal = safe_strdup (addr);
  259.  
  260.       /* reset */
  261.       p = addr;
  262.       addrlen = sizeof (addr);
  263.  
  264.       s = parse_addrspec (tmp, s + 1, host);
  265.     }
  266.     else if (*s == ',')
  267.     {
  268.       *p = 0;
  269.       if (addr[0])
  270.     parse_mailbox (tmp, addr, host);
  271.  
  272.       /* reset */
  273.       p = addr;
  274.       addrlen = sizeof (addr);
  275.  
  276.       s++;
  277.       break;
  278.     }
  279.     else if (ISSPACE (*s))
  280.     {
  281.       SKIPWS (s);
  282.  
  283.       if (p != addr)
  284.       {
  285.     if (strchr (rspecials, *s) == NULL &&
  286.         strchr (rspecials, *(p-1)) == NULL)
  287.     {
  288.       if (p != addr)
  289.       {
  290.         if (addrlen > 1)
  291.         {
  292.           *p++ = ' ';
  293.           addrlen--;
  294.         }
  295.       }
  296.     }
  297.       }
  298.     }
  299.     else
  300.     {
  301.       if (addrlen > 1)
  302.       {
  303.     *p++ = *s++;
  304.     addrlen--;
  305.       }
  306.     }
  307.   }
  308.  
  309.   *p = 0;
  310.  
  311.   if (addr[0])
  312.     parse_mailbox (tmp, addr, host);
  313.  
  314.   if (tmp->personal || tmp->mailbox || tmp->adl || tmp->host)
  315.     *a = tmp;
  316.   else
  317.     mutt_free_address (&tmp);
  318.  
  319.   return (s);
  320. }
  321.  
  322. void rfc822_parse_adrlist (ADDRESS **a, const char *s, const char *host)
  323. {
  324.   ADDRESS *pa = *a;
  325.   ADDRESS *tmp;
  326.  
  327.   while (pa && pa->next)
  328.     pa = pa->next;
  329.  
  330.   while (*s)
  331.   {
  332.     tmp = NULL;
  333.     SKIPWS (s);
  334.     s = parse_address (&tmp, s, host);
  335.     if (pa)
  336.       pa->next = tmp;
  337.     else
  338.       *a = pa = tmp;
  339.     while (pa && pa->next)
  340.       pa = pa->next;
  341.   }
  342. }
  343.  
  344. /* ----------------------------------------------------------------------------
  345.  * RFC822 writing routines
  346.  */
  347.  
  348. int rfc822_cat (char *d, size_t dlen, const char *s, const char *specials)
  349. {
  350.   size_t l;
  351.  
  352.   l = strlen (d);
  353.   d += l;
  354.   dlen -= l;
  355.  
  356.   if (strpbrk (s, specials) != NULL)
  357.   {
  358.     dlen--; /* save room for the \0 */
  359.  
  360.     if (dlen < 2)
  361.       return (-1);
  362.  
  363.     *d++ = '\"';
  364.     dlen--;
  365.  
  366.     while (*s)
  367.     {
  368.       if (*s == '\"')
  369.       {
  370.     if (dlen < 2)
  371.       return (-1);
  372.  
  373.     *d++ = '\\';
  374.     dlen--;
  375.       }
  376.       else if (dlen < 1)
  377.     return (-1);
  378.  
  379.       *d++ = *s++;
  380.       dlen--;
  381.     }
  382.  
  383.     if (dlen < 1)
  384.       return (-1);
  385.  
  386.     *d++ = '\"';
  387.     *d = 0;
  388.   }
  389.   else
  390.     strfcpy (d, s, dlen);
  391.  
  392.   return 0;
  393. }
  394.  
  395. int rfc822_address (char *s, size_t len, ADDRESS *a)
  396. {
  397.   size_t l = strlen (s);
  398.  
  399.   s += l;
  400.   len -= l;
  401.  
  402.   if (a->adl)
  403.   {
  404.     strfcpy (s, a->adl, len);
  405.     l = strlen (s);
  406.     s += l;
  407.     len -= l;
  408.  
  409.     if (len < 2)
  410.     {
  411.       *s = 0;
  412.       return (-1);
  413.     }
  414.  
  415.     *s++ = ':';
  416.     len--;
  417.   }
  418.  
  419.   if (a->mailbox)
  420.   {
  421.     if (rfc822_cat (s, len, a->mailbox, wspecials) == -1)
  422.       return (-1);
  423.  
  424.     l = strlen (s);
  425.     s += l;
  426.     len -= l;
  427.  
  428.     if (a->host)
  429.     {
  430.       if (*a->host != '@')
  431.       {
  432.     if (len < 2)
  433.     {
  434.       *s = 0;
  435.       return (-1);
  436.     }
  437.  
  438.     *s++ = '@';
  439.     len--;
  440.  
  441.     strfcpy (s, a->host, len);
  442.     l = strlen (s);
  443.     s += l;
  444.     len -= l;
  445.       }
  446.     }
  447.     else
  448.     {
  449.       /* group mailbox */
  450.  
  451.       if (len < 3)
  452.       {
  453.     *s = 0;
  454.     return (-1);
  455.       }
  456.  
  457.       *s++ = ':';
  458.       *s++ = ' ';
  459.       *s = 0;
  460.     }
  461.   }
  462.   else if (!a->host)
  463.   {
  464.     /* end of group mailbox */
  465.  
  466.     if (len < 2)
  467.     {
  468.       *s = 0;
  469.       return (-1);
  470.     }
  471.  
  472.     *s++ = ';';
  473.     *s = 0;
  474.   }
  475.  
  476.   return 0;
  477. }
  478.  
  479. int rfc822_write_address (char *s, size_t len, ADDRESS *a)
  480. {
  481.   size_t l = strlen (s);
  482.  
  483.   s += l;
  484.   len -= l;
  485.  
  486.   if (l)
  487.   {
  488.     /* previous stuff, add a comma to separate addresses */
  489.  
  490.     if (len < 3)
  491.       return (-1);
  492.  
  493.     *s++ = ',';
  494.     *s++ = ' ';
  495.     *s = 0;
  496.     len -= 2;
  497.   }
  498.  
  499.   while (a)
  500.   {
  501.     if (a->personal)
  502.     {
  503.       if (rfc822_cat (s, len, a->personal, rspecials) == -1)
  504.     return (-1);
  505.  
  506.